# Auther：wujehy
# email:wujehy@qq.com
# @File : Bridge.py
# @Time : 19-4-3 下午9:30

"""

使用确保 安装 需要的模块

python 3.6 环境


模块 serial mqtt

注意配置 串口 信息;

指令
pip3 install  -i https://pypi.tuna.tsinghua.edu.cn/simple paho-mqtt pyserial

或者

pip install  -i https://pypi.tuna.tsinghua.edu.cn/simple paho-mqtt pyserial

链接数据发送成功 有 结果查询
网址 :http://iotgeek.top:8088/getData

这个类文件是 处理
    读取 串口数据 和 解析 服务器的数据到 协调器

主要方法
    getSerialtoQueue_Thread:
        获取串口的信息到 队列 的线程

    sendtoServer :
        将 数据发送到 服务器

    Recv_Mqtt:
        接受 来自 服务器的线程,同时 发送到协调器

    putData/getData
        封装一下 消息队列 以便 后期 更改


"""
import base64
import json
import threading
import time
from queue import Queue
import requests
import serial
import paho.mqtt.client as mqtt


class Bridge():
    serial=''
    dataQueue=''
    sendQueue=''
    httptool=''
    panid='578aea14857ee64bba27e823e9d93dac'
    mqttClient=''
    mqttHost="iotgeek.top"
    mqttPort=1883
    Host='http://127.0.0.1:8000'
    status = False
    # Host='http://iotgeek.top:8088'
    def __init__(self,port = "/dev/ttyUSB0",baudrate = 9600,timeout = None,mqttHost="iotgeek.top",host='http://127.0.0.1:8000/API',panid="1234"):
        self.mqttHost=mqttHost
        self.panid=panid
        self.Host=host
        # 初始化 串口
        try:
            self.serial=serial.Serial(port=port,baudrate=baudrate,timeout=timeout)
        except:
            print("串口 配置失败 ,不存在 串口")
            return
        # 初始化 http
        self.httptool=requests.Session()
        # 初始化 mqtt
        self.mqttClient=mqtt.Client()
        self.mqttClient.connect(self.mqttHost,self.mqttPort,60)

        self.mqttClient.subscribe("wujehy", 1)
        self.mqttClient.on_message=self.Recv_Mqtt
        # 初始化 队列
        self.dataQueue=Queue(128)
        self.sendQueue=Queue(128) #这里 测试只有一个协调器 所以 用不到 配合 后端使用
        self.status = True
        return
    def getSerialtoQueue_Thread(self):
        """
        发送信息到 服务器
        监听 串口是否有数据

        有则 获取一行数据 然后放进上传 队列
        :return:
        """
        while True:
            if self.serial.readable():
                self.datas=self.serial.readline()
                data=self.datas
                self.putData(data)
                print("Test:%s "%data)
            else:
                time.sleep(1);
                pass




    def sendtoServer(self):
        """
        发送到 服务器的线程
        :return:
        """
        url=self.Host+"/upload"
        while True:
            try:
                # 如果 队列不是空的 才处理
                if not self.dataQueue.empty() :
                    data=self.getData()
                    params={
                        "data":self.base64encode(data).decode(),
                        "panid":self.panid
                    }
                    ret=self.httptool.get(url=url,params=params)
                    # 测试
                    print(ret.json())
                    time.sleep(0.1)

                else:
                    time.sleep(1)
                    pass
            except:
                time.sleep(1)
                pass
    def Recv_Mqtt(self,client, userdata, msg):
        """
        mqtt 消息接受处理

        :param client:
        :param userdata:
        :param msg:
        :return:
        """
        print(msg.topic,msg.payload)
        while True:
            # 如果发送了 ok 指令 则 请求后端的数据
            try:
                if msg.payload == self.panid.encode():
                    url = self.Host + "/status"
                    params = {
                        "panid": self.panid,
                        "status": "1"
                    }
                    data = self.httptool.get(url=url, params=params)
                    print(data.text)
                    # 如果 页面不是 空的则 具体处理 否则 当作是 错误的发送
                    if data.json()["status"] == "success":
                        print(data.json()["data"]["code"])
                        code = data.json()["data"]["code"]
                        len =data.json()["data"]["len"]
                        code = self.base64decode(code.encode())
                        print(code)
                        self.serial.write(code)
                        # 后端 将 数据处理完 就 len=0
                        if not  len>0:
                            break
                    else:
                        break
                else:
                    break
            except:
                print("error stop")
                break
            # self.sendQueue.put(data.json()[])

    # 析构函数 关闭 串口 和 mqtt
    def __del__(self):
        self.serial.close()
        self.mqttClient.loop_stop()
        self.mqttClient.disconnect()

    #   封装的方法 方便 后期
    def putData(self,data):
        self.dataQueue.put(data)

    def getData(self):
        return self.dataQueue.get()

    def base64encode(self,data):
        """
        输入的是byte
        将二进制格式转化成 字符
        :param data:
        :return:
        """
        return base64.encodebytes(data)

    def base64decode(self,data):
        """
        输入的是byte

        将字符转化 二进制
        :param data:
        :return:
        """
        return base64.decodebytes(data)
if __name__=="__main__":
    # 这里 修改 你的 Arduino 串口 和 波特率
    # 需要 安装 python3.6  和  几个 模块
    status=True

    try:
        config = {"mqttHost": "iotgeek.top", "Host": "http://127.0.0.1:8000/API", "port": "/dev/ttyUSB1",
                  "baudrate": 9600}
        # 读取配置文件
        try:
            with open("config.json", "r") as f:
                config = json.loads(f.read())
                f.close()
            pass
        except:
            pass
        # T=Bridge(port="/dev/ttyACM0",baudrate=9600)
        T =Bridge(port=config["port"],baudrate=config["baudrate"],mqttHost=config["mqttHost"],host=config["Host"],panid=config["panid"])
        print(config)
    except:
        status=False
        print("没有 必要模块 或者 串口 不存在")
    if status:
        while not T.status:
            T = Bridge()
            time.sleep(1)
        threads=[]
        threads1=threading.Thread(target=T.getSerialtoQueue_Thread)
        threads2=threading.Thread(target=T.sendtoServer)
        # for x in range(threads):
        #     threads[x].start()
        threads1.start()
        threads2.start()

        print("桥接层　以　启动完毕　，请输入指令集...")
        T.mqttClient.loop_forever()
    else:
        T.__del__()
